package com.advert.service.advert;

import com.advert.dto.image.ImageScalingResult;
import com.advert.model.advert.AdvertEntity;
import com.advert.model.advert.ImageEntity;
import com.advert.model.advert.ImageLobsEntity;
import com.advert.model.advert.search.CriteriaBase;
import com.advert.model.security.Status;
import com.advert.model.vehicle.VehicleEntity;
import com.advert.provider.advert.AdvertProvider;
import com.advert.security.AppSecurityManager;
import com.advert.service.admin.AdminService;
import com.advert.service.util.ImageProcessingService;
import org.jboss.seam.ScopeType;
import org.jboss.seam.annotations.*;

import java.io.File;
import java.io.IOException;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Map;


@Name("AdvertService")
@Scope(ScopeType.EVENT)
@AutoCreate
public class AdvertService implements Serializable {
    @In("AdvertProvider")
    private AdvertProvider advertProvider;
    @In("ImageProcessingService")
    private ImageProcessingService imageProcessingService;
    @In("SecurityManager")
    private AppSecurityManager securityManager;
    @In("AdminService")
    private AdminService adminService;
    @In("uploadedImagesDirectory")
    private File uploadedImagesDirectory;


    /**
     * In single transaction creates new advert in database and stores images in web accessed directory.
     *
     * @param advertEntity - new advert
     * @param processingResults - results of image scaling
     * @param saveImages - flag indicates whether to save images
     * @return persisted entity
     * @throws IOException - exception working with image files
     */
    @Transactional
    public AdvertEntity createAdvert(AdvertEntity advertEntity, List<ImageScalingResult> processingResults, boolean saveImages) throws IOException {
        Date today = new Date();
        List<ImageLobsEntity> images = null;
        if (saveImages) {
            images = new ArrayList<ImageLobsEntity>();
            for (ImageScalingResult processingResult : processingResults) {
                ImageLobsEntity image = imageProcessingService.buildImageLobs(processingResult);
                images.add(image);
            }
            advertEntity.setImageLobs(images);
        }

        advertEntity.getVehicle().setCreateDate(today);
        advertEntity.getVehicle().setUpdateDate(today);
        advertEntity.getVehicle().setOwnerId(securityManager.userId());
        advertEntity.setCreateDate(today);
        advertEntity.setUpdateDate(today);
        advertEntity.setOwnerId(securityManager.userId());
        advertEntity.setStatus(Status.PENDING);
        AdvertEntity retVal = advertProvider.createAdvert(advertEntity);

        if (saveImages) {
            int i = 0;
            for (ImageScalingResult result : processingResults) {
                imageProcessingService.storeImages(result, images.get(i).getId(), uploadedImagesDirectory);
                i++;
            }
        } else {
            for (ImageScalingResult processingResult : processingResults) {
                imageProcessingService.removeImages(processingResult);
            }
        }
        adminService.notifyAboutPendingAdvert();

        return retVal;
    }

    @Transactional
    public AdvertEntity updateAdvert(AdvertEntity advert, Map<Integer, Boolean> imageControl) {
        if (advert.getStatus() != Status.PENDING) {
            advert.setStatus(Status.PENDING);
            adminService.notifyAboutPendingAdvert();
        }
        AdvertEntity retVal = updateAdvert(advert);
        VehicleEntity vehicle = updateVehicle(advert.getVehicle());
        retVal.setVehicle(vehicle);
        for (ImageEntity image : advert.getImages()) {
            if (imageControl.get(image.getId()) != null && imageControl.get(image.getId())) {
                imageProcessingService.removeImage(image, uploadedImagesDirectory);
            }
        }

        return retVal;
    }

    @Transactional
    public AdvertEntity updateAdvert(AdvertEntity advert) {
        advert.setUpdateDate(new Date());
        return advertProvider.updateAdvert(advert);
    }

    @Transactional
    public void removeAdvert(Integer id) {
        AdvertEntity advert = getAdvert(id);
        advertProvider.removeAdvert(advert);

        for (ImageEntity image : advert.getImages()) {
            imageProcessingService.removeImage(image, uploadedImagesDirectory);
        }
    }

    @Transactional
    public VehicleEntity updateVehicle(VehicleEntity vehicleEntity) {
        vehicleEntity.setUpdateDate(new Date());
        return advertProvider.updateVehicle(vehicleEntity);
    }

    public List<AdvertEntity> getAdverts(CriteriaBase criteria, Integer pageNumber, int advertsToDisplay) {
        int firstIndex = (pageNumber - 1) * advertsToDisplay;
        if (firstIndex < 0) {
            firstIndex = 0;
        }
        criteria.setFirstIndex(firstIndex);
        criteria.setCount(advertsToDisplay);
        return advertProvider.getAdverts(criteria);
    }

    public int getPageCount(CriteriaBase criteria, int advertsToDisplay) {
        long advertsCount = advertProvider.getAdvertsCount(criteria);
        return (int)Math.ceil(advertsCount / (double)advertsToDisplay);
    }

    public AdvertEntity getAdvert(Integer advertId) {
        AdvertEntity retVal = null;
        if (advertId != null) {
            retVal = advertProvider.getAdvert(advertId);
        }
        return retVal;
    }
}
